﻿
//WebRequest, contains the web request methods.
LightScript.using("LightScript.Core", function()
{
    LightScript.Core.createNamespace("LightScript.Net");
    var thisClass = LightScript.Core.createClass("LightScript.Net.WebRequest");

    //# Private Members

    //# Constructions

    //# Public Members

    //# Private Methods
    function connect(socket, requestUri, uploadData, onSuccess, onError, extendParams)
    {
        //LightScript.trace(requestUri);
        socket.requestUri = requestUri;
        socket.uploadData = uploadData;
        socket.onSuccess = onSuccess;
        socket.onError = onError;
        if(extendParams)
        {
            if(extendParams.headers != undefined)
                socket.headers = extendParams.headers;
            if(extendParams.method != undefined)
                socket.method = extendParams.method;
            if(extendParams.timeout != undefined)
                socket.timeout = extendParams.timeout;            
            if(extendParams.isAsync != undefined)
                socket.isAsync = extendParams.isAsync;
        }
        socket.send();
        socket = null;
    }

    //# Public Methods
    // Creates a web request.
    // extendParams<Object>: {headers: {}, method: "get/post", timeout:20(s), isAsync: true/false}
    LightScript.Net.WebRequest.create = create;
    function create(requestUri, uploadData, onSuccess, onError, extendParams)
    {
        var requestMode;
        if(extendParams && extendParams.requestMode != undefined)  //From function parameter
            requestMode = extendParams.requestMode;
        if(!requestMode)
            requestMode = LightScript.Core.getConfig("requestMode") || "xmlhttp";   //From config or default

        switch (requestMode.toLowerCase())  //Select provider
        {
            case "xmlhttp":
                LightScript.using("LightScript.Net.XmlHttp@LightScript.Net.WebRequest", 
                    function(){connect(new LightScript.Net.XmlHttp(), requestUri, uploadData, onSuccess, onError, extendParams);});
                break;
            case "scripthttp":
                LightScript.using("LightScript.Net.ScriptHttp@LightScript.Net.WebRequest", 
                    function(){connect(new LightScript.Net.ScriptHttp(), requestUri, uploadData, onSuccess, onError, extendParams);});
                break;
            case "htmlhttp":
                LightScript.using("LightScript.Net.HtmlHttp@LightScript.Net.WebRequest", 
                    function(){connect(new LightScript.Net.HtmlHttp(), requestUri, uploadData, onSuccess, onError, extendParams);});
                break;
            default :
                break;
        }
    }

    //# Shortcuts
});


//WebResponse
LightScript.using("LightScript.Core", function()
{
    var thisClass = LightScript.Core.createClass("LightScript.Net.WebResponse");

    //# Private Members

    //# Constructions

    //# Public Members
    thisClass.prototype.responseUri = null;
    thisClass.prototype.text = null;
    thisClass.prototype.headers = null;
    thisClass.prototype.statusCode = null;
    thisClass.prototype.contentLength = null;
    thisClass.prototype.contentType = null;
    thisClass.prototype.isFromCache = null;

    //# Private Methods

    //# Public Methods

    //# Shortcuts
});


//Socket
LightScript.using("LightScript.Core", function()
{
    var thisClass = LightScript.Core.createClass("LightScript.Net.Socket");

    //# Private Members
    thisClass.prototype._connection = null;

    //# Constructions

    //# Public Members
    thisClass.prototype.requestUri = null;
    thisClass.prototype.headers = []; //Request headers, e.g: [[, ], ...]
    thisClass.prototype.method = "get";
    thisClass.prototype.uploadData = "";  //Get or post data, e.g: a=1&b=xyz
    thisClass.prototype.timeout = 20;  //Seconds
    thisClass.prototype.isAsync = true;

    //# Private Methods

    //# Public Methods
    thisClass.prototype.send = function(){LightScript.Core.markAsAbstract("send");};
    thisClass.prototype.onStateChange = function(){LightScript.Core.markAsAbstract("onStateChange");};

    //# Shortcuts
});


//XmlHttp provider
LightScript.using("LightScript.Core", "LightScript.Function", "LightScript.Net.Socket@LightScript.Net.WebRequest", function()
{
    var thisClass = LightScript.Core.createClass("LightScript.Net.XmlHttp: LightScript.Net.Socket", function()
    {
            LightScript.Core.base(this, LightScript.Net.WebRequest);
    });

    //# Private Members

    //# Constructions

    //# Public Members

    //# Private Methods
    function createConnection()
    {
        var conn = null;

        if (window.ActiveXObject)
            conn = new ActiveXObject('Microsoft.XMLHTTP');
        else if (window.XMLHttpRequest)
            conn = new XMLHttpRequest();

        return conn;
    }

    // Determines if an XMLHttpRequest was successful or not
    function isHttpSuccess(conn)
    {
        // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
        return !conn.status && document.location.protocol == "file:" ||
            (conn.status >= 200 && conn.status < 300) || conn.status == 304 || conn.status == 1223;
    }

    //# Public Methods
    thisClass.prototype.send = function()
    {
        var conn = createConnection();
        if(!conn)
            throw new LightScript.Exception(Error, arguments, LightScript.message.notSupportXmlHttp, conn);

        this._connection = conn;
        conn.open(this.method, this.requestUri, this.isAsync);
        conn.onreadystatechange = LightScript.Function.createDelegate(this.onStateChange, this);
        if (this.method == "post")
        {
            conn.setRequestHeader("content-type", "application/x-www-form-urlencoded");
            if (conn.overrideMimeType) conn.setRequestHeader("connection", "close");
        }
        if(this.headers)
        {
            for (var i = 0, len = this.headers.length; i < len; i++)
                conn.setRequestHeader(this.headers[i][0], this.headers[i][1]);
        }
        conn.send(this.uploadData);
    };

    thisClass.prototype.onStateChange = function()
    {
        var conn = this._connection;

        if(conn.readyState == 4)
        {
            if(isHttpSuccess(conn))  //Success
            {                
                var response = new LightScript.Net.WebResponse();
                //response.responseUri = null;
                response.text = conn.responseText;
                //Fill in response headers
                response.headers = {};
                var headers = conn.getAllResponseHeaders().split("\n");
                var pair;
                for (var i = 0, len = headers.length; i < len; i++)
                {
                    pair = headers[i].split(": ");
                    if(pair.length == 1) continue;
                    response.headers[(pair[0]+"").toLowerCase()] = pair[1];
                }
                response.statusCode = conn.status;
                response.contentLength = conn.getResponseHeader("content-length");
                response.contentType = conn.getResponseHeader("content-type");
                response.isFromCache = conn.status == 304;
                if(this.onSuccess)
                    this.onSuccess(response);
            }
            else
            {
                if(this.onError)
                    this.onError(conn.status);
            }
            delete conn.onreadystatechange;
            this._connection = null;
        }
    };

    //# Shortcuts
});


//ScriptHttp provider
LightScript.using("LightScript.Core", "LightScript.Function", "LightScript.Net.Socket@LightScript.Net.WebRequest", function()
{
    var thisClass = LightScript.Core.createClass("LightScript.Net.ScriptHttp: LightScript.Net.Socket");

    //# Private Members

    //# Constructions

    //# Public Members
    thisClass.prototype.contentType = "text/javascript";
    thisClass.prototype.charset = "utf-8";

    //# Private Methods

    //# Public Methods
    thisClass.prototype.send = function()
    {
        var onStateChangeDelegate = LightScript.Function.createDelegate(this.onStateChange, this);
        var url = this.requestUri;
        if(this.uploadData)
            url += "?" + this.uploadData;

        LightScript.Core.loadScript(url, onStateChangeDelegate, 
            {type: this.contentType, charset: this.charset});
    }

    thisClass.prototype.onStateChange = function()
    {
        //There is only success state till now.
        if(this.onSuccess)
            this.onSuccess(null);
    }

    //# Shortcuts
});


//HtmlHttp provider
LightScript.using("LightScript.Core", "LightScript.Bom", "LightScript.Function", "LightScript.Net.Socket@LightScript.Net.WebRequest", function()
{
    var thisClass = LightScript.Core.createClass("LightScript.Net.HtmlHttp: LightScript.Net.Socket");

    //# Private Members

    //# Constructions

    //# Public Members

    //# Private Methods
    function createConnection(method, uploadData)
    {
        var span = document.createElement("span");
        var name = "ls_" + LightScript.Core.newId();
        span.style.width = "0px";
        span.style.height = "0px";
        span.style.display = "none";
        span.innerHTML = "<iframe width='0' height='0' name='" + name + "'></iframe>";
        document.body.appendChild(span);
        var conn = span.childNodes[0];

        if(method == "post")
        {
            conn.formId = "ls_" + LightScript.Core.newId();
            var frm = document.createElement("form");
            frm.id = conn.formId;
            frm.name = conn.formId;
            frm.method = method;
            frm.target = conn.name;
            if(uploadData)
            {
                //a=1&b=2
                var params = uploadData.split("&");
                var segs, field;
                for (var i = 0, len = params.length; i < len; i++)
                {
                    segs = params[i].split("=");
                    field = document.createElement("input");
                    field.type = "hidden";
                    field.name = segs[0];
                    field.value = segs[1];
                    frm.appendChild(field);
                }
            }
            span.appendChild(frm);
        }

        return conn;
    }

    //# Public Methods
    thisClass.prototype.send = function()
    {
        var conn = createConnection(this.method, this.uploadData);
        this._connection = conn;
        conn.onload = conn.onreadystatechange = LightScript.Function.createDelegate(this.onStateChange, this);
        var url = this.requestUri;
        if(this.method == "get")
        {
            if(this.uploadData)
                url += "?" + this.uploadData;
            conn.src = url;
        }
        else if(this.method == "post")
        {
            var frm = document.forms[conn.formId];
            frm.action = url;
            frm.submit();
        }
    }

    thisClass.prototype.onStateChange = function()
    {
        var conn = this._connection;
        if (conn.readyState && conn.readyState != "loaded" && conn.readyState != "complete") return;
        conn.onreadystatechange = conn.onload = null;

        var response = new LightScript.Net.WebResponse();
        try
        {
            var win = window[conn.name];
            response.responseUri = win.location.href;            
            //response.text = win.document.documentElement.outerHTML;
            response.text = win.document.body.innerHTML;
        }
        catch (ex)
        {
            throw new LightScript.Exception(Error, arguments, LightScript.message.htmlHttpError, ex.description, ex);
        }
        if(response.text != undefined)
            response.contentLength  = response.text.length;

        conn.parentNode.parentNode.removeChild(conn.parentNode);   //Remove the conn element

        //There is only success state till now.
        if(this.onSuccess)
            this.onSuccess(response);
    }

    //# Shortcuts
});
